// bmp.cpp
#include "./../inc/main.h"

using namespace std;
BMP::BMP(const char *bmp_path)
{
    // 打开图片
    this->fd = open(bmp_path, O_RDONLY);
    if (this->fd == -1)
    {
        perror("[error] bmp open");
    }

    // 获取图片宽度和高度
    lseek(this->fd, 18, SEEK_SET);
    read(this->fd, &this->m_width, sizeof(int));
    read(this->fd, &this->m_height, sizeof(int));

    // std::cout<<"w ="<<this->m_width<<"h ="<<this->m_height<<std::endl;

    // 获取图片数据大小
    this->m_size = this->m_width * this->m_height * 3;

    // 申请空间存放图片数据，不读取补齐的字节
    this->m_buf = new char[this->m_size];

    // 计算补齐字节数
    int skip_byte = 0;
    if (this->m_width * 3 % 4 != 0)
    {
        skip_byte = 4 - (this->m_width * 3 % 4);
    }

    // 读取图片数据
    lseek(this->fd, 54, SEEK_SET);

    // 倒置存放图片数据
    char *tmp_ptr = this->m_buf;
    tmp_ptr += this->m_size;

    for (int i = 0; i < this->m_height; i++)
    {
        tmp_ptr -= this->m_width * 3; // 要先减是因为读取是向后保存的，如果没有先减就越界了哦！
        read(this->fd, tmp_ptr, this->m_width * 3);
        lseek(this->fd, skip_byte, SEEK_CUR); // 跳过每行的补齐字节，不读取他们
    }
    ::close(this->fd);
}

BMP::~BMP()
{
    delete[] this->m_buf;
}

char BMP::operator[](int index)
{
    return this->m_buf[index];
}

char *BMP::addr() const
{
    return this->m_buf;
}

void BMP::show(int *mp, int x, int y)
{
    for (int i = 0, n = 0; i < this->m_height; i++)
    {
        for (int j = 0; j < this->m_width; j++, n += 3)
        {
            int posX = j + x;
            int posY = i + y;
            if (posX >= 0 && posX < LCD_WIDTH && posY >= 0 && posY < LCD_HEIGHT)
            {
                *(mp + LCD_WIDTH * posY + posX) =
                    this->m_buf[n] << 0 | this->m_buf[n + 1] << 8 | this->m_buf[n + 2] << 16;
            }
        }
    }
}

int BMP::width() const
{
    return m_width;
}

int BMP::height() const
{
    return m_height;
}

// 绘制空心圆圈
void BMP::drawCircle(int *mp, int centerX, int centerY, int radius, int color)
{
    int x = radius;
    int y = 0;
    int err = 0;

    while (x >= y)
    {
        // 绘制8个对称点
        int posX1 = centerX + x;
        int posY1 = centerY + y;
        int posX2 = centerX + y;
        int posY2 = centerY + x;
        int posX3 = centerX - y;
        int posY3 = centerY + x;
        int posX4 = centerX - x;
        int posY4 = centerY + y;
        int posX5 = centerX - x;
        int posY5 = centerY - y;
        int posX6 = centerX - y;
        int posY6 = centerY - x;
        int posX7 = centerX + y;
        int posY7 = centerY - x;
        int posX8 = centerX + x;
        int posY8 = centerY - y;

        // 检查边界并绘制
        if (posX1 >= 0 && posX1 < LCD_WIDTH && posY1 >= 0 && posY1 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY1 + posX1) = color;
        if (posX2 >= 0 && posX2 < LCD_WIDTH && posY2 >= 0 && posY2 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY2 + posX2) = color;
        if (posX3 >= 0 && posX3 < LCD_WIDTH && posY3 >= 0 && posY3 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY3 + posX3) = color;
        if (posX4 >= 0 && posX4 < LCD_WIDTH && posY4 >= 0 && posY4 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY4 + posX4) = color;
        if (posX5 >= 0 && posX5 < LCD_WIDTH && posY5 >= 0 && posY5 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY5 + posX5) = color;
        if (posX6 >= 0 && posX6 < LCD_WIDTH && posY6 >= 0 && posY6 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY6 + posX6) = color;
        if (posX7 >= 0 && posX7 < LCD_WIDTH && posY7 >= 0 && posY7 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY7 + posX7) = color;
        if (posX8 >= 0 && posX8 < LCD_WIDTH && posY8 >= 0 && posY8 < LCD_HEIGHT)
            *(mp + LCD_WIDTH * posY8 + posX8) = color;

        if (err <= 0)
        {
            y += 1;
            err += 2 * y + 1;
        }

        if (err > 0)
        {
            x -= 1;
            err -= 2 * x + 1;
        }
    }
}

void BMP::drawRectangle(int *mp, int x1, int y1, int x2, int y2, int color, int lineWidth)
{
    // 确保x1 <= x2, y1 <= y2
    if (x1 > x2)
        swap(x1, x2);
    if (y1 > y2)
        swap(y1, y2);

    // 绘制上下边
    for (int w = 0; w < lineWidth; w++)
    {
        for (int x = x1; x <= x2; x++)
        {
            int yTop = y1 + w;
            int yBottom = y2 - w;

            if (yTop >= 0 && yTop < LCD_HEIGHT)
            {
                if (x >= 0 && x < LCD_WIDTH)
                {
                    *(mp + LCD_WIDTH * yTop + x) = color;
                }
            }

            if (yBottom >= 0 && yBottom < LCD_HEIGHT && yBottom != yTop)
            {
                if (x >= 0 && x < LCD_WIDTH)
                {
                    *(mp + LCD_WIDTH * yBottom + x) = color;
                }
            }
        }
    }

    // 绘制左右边
    for (int w = 0; w < lineWidth; w++)
    {
        for (int y = y1 + lineWidth; y <= y2 - lineWidth; y++)
        {
            int xLeft = x1 + w;
            int xRight = x2 - w;

            if (xLeft >= 0 && xLeft < LCD_WIDTH)
            {
                if (y >= 0 && y < LCD_HEIGHT)
                {
                    *(mp + LCD_WIDTH * y + xLeft) = color;
                }
            }

            if (xRight >= 0 && xRight < LCD_WIDTH && xRight != xLeft)
            {
                if (y >= 0 && y < LCD_HEIGHT)
                {
                    *(mp + LCD_WIDTH * y + xRight) = color;
                }
            }
        }
    }
}

// 绘制圆角矩形
void BMP::drawRoundRectangle(int *mp, int x1, int y1, int x2, int y2, int fillColor,
                             int radius, int borderColor, int lineWidth)
{
    // 确保坐标合法性
    if (x1 >= x2 || y1 >= y2)
        return;
    radius = min(radius, (x2 - x1) / 2); // 限制最大半径为半宽
    radius = min(radius, (y2 - y1) / 2); // 限制最大半径为半高

    // 1. 填充圆角矩形内部
    for (int y = y1; y <= y2; y++)
    {
        for (int x = x1; x <= x2; x++)
        {
            // 跳过四角的圆角区域
            bool inLeftTop = (x < x1 + radius) && (y < y1 + radius);
            bool inRightTop = (x > x2 - radius) && (y < y1 + radius);
            bool inLeftBottom = (x < x1 + radius) && (y > y2 - radius);
            bool inRightBottom = (x > x2 - radius) && (y > y2 - radius);
            if (inLeftTop || inRightTop || inLeftBottom || inRightBottom)
                continue;

            // 填充中间矩形区域
            if (x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT)
            {
                mp[LCD_WIDTH * y + x] = fillColor;
            }
        }
    }

    // 绘制四个圆角
    auto drawCircleQuadrant = [&](int cx, int cy, bool isTop, bool isLeft)
    {
        for (int dy = 0; dy <= radius; dy++)
        {
            int dx = sqrt(radius * radius - dy * dy); // 圆弧上的x偏移
            int startX = isLeft ? (cx - dx) : (cx);
            int endX = isLeft ? (cx) : (cx + dx);
            int y = isTop ? (cy + dy) : (cy - dy);

            if (y < y1 || y > y2)
                continue; // 超出矩形范围不绘制
            for (int x = startX; x <= endX; x++)
            {
                if (x >= x1 && x <= x2 && x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT)
                {
                    mp[LCD_WIDTH * y + x] = fillColor;
                }
            }
        }
    };

    // 左上角圆角
    drawCircleQuadrant(x1 + radius, y1 + radius, true, true);
    // 右上角圆角
    drawCircleQuadrant(x2 - radius, y1 + radius, true, false);
    // 左下角圆角
    drawCircleQuadrant(x1 + radius, y2 - radius, false, true);
    // 右下角圆角
    drawCircleQuadrant(x2 - radius, y2 - radius, false, false);

    // 绘制边框
    if (lineWidth > 0 && borderColor != fillColor)
    {
        // 绘制上下边
        for (int y : {y1, y2})
        {
            for (int x = x1 + radius; x <= x2 - radius; x++)
            {
                if (x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT)
                {
                    mp[LCD_WIDTH * y + x] = borderColor;
                }
            }
        }
        // 绘制左右边
        for (int x : {x1, x2})
        {
            for (int y = y1 + radius; y <= y2 - radius; y++)
            {
                if (x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT)
                {
                    mp[LCD_WIDTH * y + x] = borderColor;
                }
            }
        }
        // 绘制四个圆角边框
        auto drawBorderQuadrant = [&](int cx, int cy, bool isTop, bool isLeft)
        {
            for (int dy = 0; dy <= radius; dy++)
            {
                int dx = sqrt(radius * radius - dy * dy);
                int x = isLeft ? (cx - dx) : (cx + dx);
                int y = isTop ? (cy + dy) : (cy - dy);
                if (x >= x1 && x <= x2 && y >= y1 && y <= y2 &&
                    x >= 0 && x < LCD_WIDTH && y >= 0 && y < LCD_HEIGHT)
                {
                    mp[LCD_WIDTH * y + x] = borderColor;
                }
            }
        };
        drawBorderQuadrant(x1 + radius, y1 + radius, true, true);
        drawBorderQuadrant(x2 - radius, y1 + radius, true, false);
        drawBorderQuadrant(x1 + radius, y2 - radius, false, true);
        drawBorderQuadrant(x2 - radius, y2 - radius, false, false);
    }
}